package com.devops.utils.ssh;

import cn.hutool.core.util.ObjectUtil;
import com.devops.entity.req.SshInfo;
import com.devops.entity.resp.ErrorReason;
import com.devops.utils.error.ReturnErrorException;
import com.devops.utils.error.ReturnResultType;
import com.devops.utils.executor.ChannelCallable;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;

import java.util.*;
import java.util.concurrent.*;

/**
 * 存储ssh session的定量值的信息
 * ps:后期可以试一下LRU算法
 * session ChannelExec使用线程池，按ip位置分配线程
 */
public class SshRestoreUtil {

    private static final int MAX_LENGTH = 2;
    private static LinkedList<String> sessionList = new LinkedList<>();
    private static LinkedHashMap<String, Session> sessionMap = new LinkedHashMap<>();
    private static LinkedHashMap<String, ChannelSftp> channelSftpMap = new LinkedHashMap<>();
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(MAX_LENGTH, MAX_LENGTH * 2, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

    // 查询map
    public static boolean hasValue(String key) throws ReturnErrorException {
        if (sessionMap.containsKey(key)) {
            Session session = sessionMap.get(key);
            if (!session.isConnected()) {
                remove(key);
                return false;
            }
            return true;
        }
        return false;
    }

    // 插入map
    public static boolean setValue(String key, Session session) throws ReturnErrorException {
        try {
            int length = sessionMap.size();
            if (length > MAX_LENGTH || sessionList.size() > MAX_LENGTH) {
                String sessionKey = sessionList.get(0);
                remove(sessionKey);
            }
            sessionMap.put(key, session);
            return true;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("插入map失败"));
        }
    }

    // 移出map
    public static boolean remove(String key) throws ReturnErrorException {
        try {
            sessionMap.get(key).disconnect();
            sessionMap.remove(key);
            sessionList.remove(key);
            channelSftpMap.get(key).disconnect();
            channelSftpMap.remove(key);
            return true;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("移出map失败"));
        }
    }

    // 查询map
    public static Session getSession(String key) throws ReturnErrorException {
        try {
            if (hasValue(key)) {
                return sessionMap.get(key);
            }
            return null;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("查询map失败"));
        }
    }

    // 查询全部的map
    public static List<SshInfo> getAllSession() throws ReturnErrorException {
        try {
            List<SshInfo> sshInfoList = new ArrayList<>();
            Set<String> sessionSets = sessionMap.keySet();
            Iterator<String> sessionIterator = sessionSets.iterator();
            if (sessionIterator.hasNext()) {
                String key = sessionIterator.next();
                Session session = sessionMap.get(key);
                SshInfo sshInfo = new SshInfo();
                sshInfo.setHostIp(key);
                sshInfo.setHostPort(session.getPort());
                sshInfo.setUserName(session.getUserName());
                sshInfoList.add(sshInfo);
            }
            return sshInfoList;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("查询map失败"));
        }
    }

    public static boolean setValueChannelSftp(String key) throws ReturnErrorException {
        try {
            channelSftpMap.put(key, setSftpChannel(key));
            return true;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("插入map失败"));
        }
    }

    public static boolean hasValueSftp(String key) throws ReturnErrorException {
        if (channelSftpMap.containsKey(key)) {
            ChannelSftp channelSftp = channelSftpMap.get(key);
            if (!channelSftp.isConnected()) {
                channelSftpMap.get(key).disconnect();
                channelSftpMap.remove(key);
                return false;
            }
            return true;
        }
        return false;
    }

    // 查询map
    public static ChannelSftp getSftp(String key) throws ReturnErrorException {
        try {
            if (hasValue(key)) {
                return channelSftpMap.get(key);
            }
            return null;
        } catch (Exception e) {
            throw new ReturnErrorException(ReturnResultType.MAP_ERROR, new ErrorReason("查询map失败"));
        }
    }

    public static ChannelSftp setSftpChannel(String hostIp) throws ReturnErrorException {
        Session session = SshRestoreUtil.getSession(hostIp);
        if (!ObjectUtil.isEmpty(session)) {
            ChannelSftp channelSftp = null;
            try {
                channelSftp = (ChannelSftp) session.openChannel("sftp");
                channelSftp.connect();
                return channelSftp;
            } catch (Exception e) {
                throw new ReturnErrorException(ReturnResultType.OPERATOR_ERROR, new ErrorReason("文件上传失败"));
            }
        } else {
            throw new ReturnErrorException(ReturnResultType.OPERATOR_ERROR, new ErrorReason("连接失败:未知异常"));
        }
    }

    public static void setChannel() {
        ChannelCallable channelCallable = new ChannelCallable("1");
        executor.submit(channelCallable);
    }

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(MAX_LENGTH, MAX_LENGTH * 2, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    }

}
